# -*- coding:utf-8 -*-
import zmq
import configparser
import time
import os
import re
import json
import threading
import sys
import traceback
import zipfile
import shutil
from update.tools.w_update_send import EchoHandler
from socketserver import BaseRequestHandler, TCPServer, ThreadingTCPServer

class server_cu(object):
    def __init__(self):
        self.config_file = r'update/tools/config.ini'
        self.Equipment_file = r'update/tools/Equipment.ini'
        self.Equipment = configparser.ConfigParser()
        self.Equipment.read(self.Equipment_file)
        self.config = configparser.ConfigParser()
        self.config.read(self.config_file)
        self.updata_status = True
        self.send_status = True

    def pub_zcell_all(self,zcell_list, zcell_rules):
        pzacontext = zmq.Context()
        pub_socket = pzacontext.socket(zmq.PUB)
        pub_port = self.config.get('ports','up_pub_port')
        pub_socket.bind("tcp://*:%s" % pub_port)
        sleep_time = 1
        # pza_poll = zmq.Poller()
        # pza_poll.register(pub_socket, zmq.POLLIN)
        while self.updata_status:
            # pza_socks = dict(pza_poll.poll(120000))
            # if pza_socks.get(pub_socket) == zmq.POLLIN:
            for i in zcell_list:
                msg = i + "|" + zcell_rules
                print("->", msg)
                pub_socket.send_string(msg)
            time.sleep(sleep_time)
            sleep_time += 1
            # else:
            #     print('广播通知较长时间无返回，程序结束')
            #     os._exit(1)
        pub_socket.close()
        pzacontext.destroy()
        return

    def pub_zcell_one(self,zcell_list):
        pzocontext = zmq.Context()
        pub_socket = pzocontext.socket(zmq.PUB)
        pub_port = self.config.get('ports','up_pub_port')
        pub_socket.bind("tcp://*:%s" % pub_port)
        sleep_time = 1
        # pzo_poll = zmq.Poller()
        # pzo_poll.register(pub_socket, zmq.POLLIN)
        while self.updata_status:
            # pza_socks = dict(pzo_poll.poll(120000))
            # if pza_socks.get(pub_socket) == zmq.POLLIN:
            for i in zcell_list:
                msg = i["id"] + "|" + str(i["module"]) + "|"
                print("->", msg)
                pub_socket.send_string(msg)
            time.sleep(sleep_time)
            sleep_time += 1
            # else:
            #     print('广播通知较长时间无返回，程序结束')
            #     os._exit(1)
        pub_socket.close()
        pzocontext.destroy()
        return

    #数据交互判断更新数量，并通知c开始进行socket连接 
    def rep_zcell(self, zcell_list):
        rep_port = self.config.get('ports', 'up_rep_port')
        rep_socket = context.socket(zmq.REP)
        rep_socket.bind("tcp://*:%s" % rep_port)
        rz_poll = zmq.Poller()
        rz_poll.register(rep_socket, zmq.POLLIN)
        global zcell_json_list
        zcell_json_list = []
        n = 0
        while self.updata_status:
            try:
                rz_socks = dict(rz_poll.poll(60000))
                if rz_socks.get(rep_socket) == zmq.POLLIN:
                    msg = rep_socket.recv_string()
                    if msg == 'one':
                        zcell_json_list = zcell_list
                        n += 1
                        rep_socket.send_string('开始更新了')
                        if len(zcell_list) == n:
                            zcell_json_list = zcell_list
                            print('rep_zcell停止，数据匹配一致')
                            self.updata_status = False
                            rep_socket.close()
                    else:
                        msg_json = json.loads(msg)
                        print(msg)
                        try:
                            zcell_json_list.index(msg_json)
                        except:
                            zcell_json_list.append(msg_json)
                        rep_socket.send_string('开始更新了')
                        if len(zcell_json_list) == len(zcell_list):
                            print('rep_zcell停止，数据匹配一致')
                            rep_socket.close()
                            self.updata_status = False
                else:
                    print('通知更新时连接超时，程序终止')
                    self.updata_status = False
                    os._exit(2)
            except BaseException as b:  # 所有异常的基类
                print('deployment_zip str(e):\t\t', str(b))  # 简单
                print('deployment_zip repr(e):\t', repr(b))  # 较简单
                print('deployment_zip traceback.print_exc(): %s' % traceback.print_exc())  # 最详细
                os._exit(1)
            except:
                print('deployment_zip traceback.print_exc(): %s' % traceback.print_exc())  # 最详细
                os._exit(1)
        return
    
    def updata_file(self):
        module_name = []
        module_rules = []
        try:
            updata_file=self.config.get('service_side','updata_file')
            list1 = os.listdir(updata_file)
            for iterm in list1:
                updata1 = updata_file + '/' + iterm
                if len(os.listdir(updata1)) != 0:
                    name = self.Equipment.get("Equipment1", iterm)
                    name_zip = name + '.zip'
                    updata2 = updata_file + '/' + name_zip
                    self.start_zip(updata1, updata2)
                    list2 = os.listdir(updata1)
                    if name_zip in list2:
                        module_name.append(name)
                        module_rules.append(re.compile(r'%s' % name))
            print(module_name, module_rules)
        except BaseException as b:  # 所有异常的基类
            print('updata_file str(e):\t\t', str(b))  # 简单
            print('updata_file repr(e):\t', repr(b))  # 较简单
            print('updata_file traceback.print_exc(): %s' % traceback.print_exc())  # 最详细
            os._exit(1)
        except:
            print('updata_file traceback.print_exc(): %s' % traceback.print_exc())  # 最详细
            os._exit(1)
        return module_rules, module_name

    def start_zip(self, f1, f2):
        try:
            pre_len = len(f1)
            zipf = zipfile.ZipFile(f2, 'w')
            for parent, dirnames, filenames in os.walk(f1):
                for filename in filenames:
                    pathfile = os.path.join(parent, filename)
                    arcname = pathfile[pre_len:].strip(os.path.sep)
                    zipf.write(pathfile, arcname, compress_type=zipfile.ZIP_DEFLATED)
            zipf.close()
            shutil.move(f2, f1)
        except BaseException as b:  # 所有异常的基类
            print('start_zip str(e):\t\t', str(b))  # 简单
            print('start_zip repr(e):\t', repr(b))  # 较简单
            print('start_zip traceback.print_exc(): %s' % traceback.print_exc())  # 最详细
            os._exit(1)
        except:
            print('start_zip traceback.print_exc(): %s' % traceback.print_exc())  # 最详细
            os._exit(1)
        return
    
    def start_zip_thread(self):
        #thread_port = self.config.get('ports', 'thread_logo_1')
        updata_list = []
        for i in zcell_json_list:
            updata_list.append(i["id"])
        print(updata_list)
        already_updata_list = []
        thread_socket_host = self.config.get('ports', 'thread_up_host')
        thread_socket_post1 = self.config.get('ports', 'thread_up_rep1_port')
        thread_socket_post2 = self.config.get('ports', 'thread_up_rep2_port')
        while self.send_status:
            try:
                print('开始接受消息')
                thread_socket = context.socket(zmq.REP)
                thread_socket.bind("tcp://%s:%s" % (thread_socket_host, thread_socket_post1))
                con_ip = thread_socket.recv_string()
                print('接收到的ip：%s' % con_ip)
                thread_status = 0
                send_thread_data = json.dumps(zcell_json_list)
                thread_socket.send_string(send_thread_data)
                print('告知server端发送数据包线程')
                thread_socket.close()
                thread_socket_2 = context.socket(zmq.REP)
                thread_socket_2.bind("tcp://%s:%s" % (thread_socket_host, thread_socket_post2))
                status = thread_socket_2.recv_string()
                print('获取更新反馈的状态值：%s' % status)
                thread_socket_2.close()
                
                if status == "error":
                    print('无法匹配到对应的模块名称，程序结束')
                    serv.shutdown()
                    serv.server_close()
                    self.send_status = False
                    os._exit(2)

                already_updata_list.append(status)
                not_updated_list = [item for item in updata_list if item not in already_updata_list]
                if len(not_updated_list) == 0:
                    print('更新成功，关闭所有线程')
                    serv.shutdown()
                    serv.server_close()
                    self.send_status = False
                else:
                    print('当前已经更新、未更新的list')
                    print(updata_list)
                    print(already_updata_list)

            except BaseException as b:  # 所有异常的基类
                print('start_zip str(e):\t\t', str(b))  # 简单
                print('start_zip repr(e):\t', repr(b))  # 较简单
                print('start_zip traceback.print_exc(): %s' % traceback.print_exc())  # 最详细
                os._exit(1)
            except:
                print('start_zip traceback.print_exc(): %s' % traceback.print_exc())  # 最详细
                os._exit(1)
        return
    
    def start_zip_send(self):
        #NWORKERS = 1
        socket_post = int(self.config.get('update','socket_port'))
        global serv
        serv = TCPServer(('', socket_post), EchoHandler)
        #for n in range(NWORKERS):
            #t = threading.Thread(target=serv.serve_forever)
            #t.daemon = True
            #t.start()
        print('开启socketserver服务')
        serv.serve_forever(poll_interval=0.5)
        print('关闭socketserver服务')
        
    
    def main_body(self,name,status):
        ##################
        ##全部更新：根据更新包存放的目录文件来判断需要更新的模块，状态为：1
        ##选择更新：根据选择更新模块，状态为：2
        ##################
        global context
        context = zmq.Context()
        update_status = status
        if update_status == 1:
            zcell_list = name
            zcell_rules, zcell_name = self.updata_file()
            t3 = threading.Thread(target=self.start_zip_send)
            t3.start()
            t1 = threading.Thread(target=self.pub_zcell_all, args=(zcell_list, repr(zcell_rules),))
            t2 = threading.Thread(target=self.rep_zcell, args=(zcell_list,))
            t4 = threading.Thread(target=self.start_zip_thread)
            t1.start()
            t2.start()
            t1.join()
            t2.join()
            t4.start()
            t4.join()
        elif update_status == 2:
            zcell_list = name
            self.updata_file()
            t3 = threading.Thread(target=self.start_zip_send)
            t3.start()
            t1 = threading.Thread(target=self.pub_zcell_one, args=(zcell_list,))
            t2 = threading.Thread(target=self.rep_zcell, args=(zcell_list,))
            t4 = threading.Thread(target=self.start_zip_thread)
            t1.start()
            t2.start()
            t1.join()
            t2.join()
            print('t4 start')
            t4.start()
            t4.join()
        else:
            print("更新类型出错，值不是1或2")
            os._exit(1)
        context.destroy()